
import uuid
from datetime import datetime
from enum import Enum
from typing import Dict, List, Optional, Set, Tuple
from dataclasses import dataclass
from abc import ABC, abstractmethod
import hashlib
import json
from collections import defaultdict

# 三元生态类型
class EcoType(Enum):
    NATURAL = "自然生态"      # 环保、可持续、与自然和谐
    HUMANISTIC = "人文生态"   # 文化传承、社会责任、人文关怀
    DIGITAL = "数字生态"      # 技术创新、数字化、智能化

# 用户角色
class UserRole(Enum):
    STUDENT = "学生"
    TEACHER = "教师"
    RESEARCHER = "研究员"
    PARENT = "家长"
    ADMIN = "管理员"

# 内容类型
class ContentType(Enum):
    TEXT = "文本"
    IMAGE = "图片"
    VIDEO = "视频"
    AUDIO = "音频"
    INTERACTIVE = "交互内容"
    ASSESSMENT = "测评"

# 学科分类
class Subject(Enum):
    CHINESE = "语文"
    MATH = "数学"
    ENGLISH = "英语"
    PHYSICS = "物理"
    CHEMISTRY = "化学"
    BIOLOGY = "生物"
    HISTORY = "历史"
    GEOGRAPHY = "地理"
    POLITICS = "政治"
    ART = "美术"
    MUSIC = "音乐"
    PE = "体育"
    TECHNOLOGY = "信息技术"
    ECOLOGY = "生态教育"  # 新增学科，体现三元生态理念

# 知识节点难度
class DifficultyLevel(Enum):
    EASY = "容易"
    MEDIUM = "中等"
    HARD = "困难"
    ADVANCED = "进阶"

@dataclass
class User:
    id: str
    username: str
    role: UserRole
    grade: Optional[str] = None  # 学生所在年级
    subject: Optional[Subject] = None  # 教师/研究员教授的学科
    children: List[str] = None  # 家长的子女ID列表
    eco_profile: Dict[EcoType, float] = None  # 用户的三元生态画像
    
    def __post_init__(self):
        if self.children is None:
            self.children = []
        if self.eco_profile is None:
            self.eco_profile = {
                EcoType.NATURAL: 0.5,
                EcoType.HUMANISTIC: 0.5,
                EcoType.DIGITAL: 0.5
            }

@dataclass
class KnowledgeNode:
    id: str
    title: str
    content: str
    content_type: ContentType
    subject: Subject
    difficulty: DifficultyLevel
    prerequisites: List[str]  # 先修知识节点ID列表
    eco_aspects: Dict[EcoType, float]  # 知识点的三元生态维度评分
    created_by: str  # 创建者ID
    created_at: datetime
    updated_at: datetime
    version: int
    ratings: Dict[str, int] = None  # 用户评分 {用户ID: 评分}
    tags: Set[str] = None
    
    def __post_init__(self):
        if self.ratings is None:
            self.ratings = {}
        if self.tags is None:
            self.tags = set()
    
    def average_rating(self) -> float:
        if not self.ratings:
            return 0.0
        return sum(self.ratings.values()) / len(self.ratings)
    
    def update_content(self, new_content: str, updated_by: str) -> None:
        self.content = new_content
        self.updated_at = datetime.now()
        self.version += 1
        # 记录更新历史
        KnowledgeHistory.record_update(self.id, updated_by, self.version)

@dataclass
class LearningPath:
    id: str
    name: str
    description: str
    subject: Subject
    target_grade: str  # 目标年级
    nodes: List[str]  # 知识节点ID列表
    created_by: str
    eco_balance: Dict[EcoType, float]  # 学习路径的三元生态平衡
    version: int
    ratings: Dict[str, int] = None
    
    def __post_init__(self):
        if self.ratings is None:
            self.ratings = {}
    
    def add_node(self, node_id: str, position: int = None) -> None:
        if position is None:
            self.nodes.append(node_id)
        else:
            self.nodes.insert(position, node_id)
    
    def remove_node(self, node_id: str) -> bool:
        if node_id in self.nodes:
            self.nodes.remove(node_id)
            return True
        return False

@dataclass
class TeachingGroup:
    id: str
    name: str
    subject: Subject
    grade_level: str  # 针对的年级
    members: List[str]  # 成员用户ID列表
    created_at: datetime
    current_projects: List[str] = None  # 当前进行的项目/教材编写任务
    
    def __post_init__(self):
        if self.current_projects is None:
            self.current_projects = []

@dataclass
class ResearchGroup:
    id: str
    name: str
    focus_areas: List[Subject]  # 研究重点领域
    members: List[str]  # 成员用户ID列表
    research_projects: List[str] = None  # 研究项目列表
    
    def __post_init__(self):
        if self.research_projects is None:
            self.research_projects = []

@dataclass
class ParentAssociation:
    id: str
    school: str  # 所属学校
    grade: str  # 所属年级
    members: List[str]  # 家长用户ID列表
    feedback_items: List[str] = None  # 反馈项目ID列表
    
    def __post_init__(self):
        if self.feedback_items is None:
            self.feedback_items = []

@dataclass
class Feedback:
    id: str
    content: str
    created_by: str  # 提交者ID
    created_at: datetime
    target_type: str  # 反馈对象类型: knowledge_node, learning_path, etc.
    target_id: str  # 反馈对象ID
    priority: int  # 优先级 1-5
    status: str  # pending, in_progress, resolved

@dataclass
class KnowledgeHistory:
    """知识节点更新历史记录"""
    node_id: str
    version: int
    content: str
    updated_by: str
    updated_at: datetime
    change_description: str
    
    @classmethod
    def record_update(cls, node_id: str, updated_by: str, version: int, 
                     change_description: str = "内容更新") -> None:
        # 在实际实现中，这里会将更新记录保存到数据库
        pass

class DynamicTextbookSystem:
    """寰宇光锥舟全国动态教材系统"""
    
    def __init__(self):
        self.users: Dict[str, User] = {}
        self.knowledge_nodes: Dict[str, KnowledgeNode] = {}
        self.learning_paths: Dict[str, LearningPath] = {}
        self.teaching_groups: Dict[str, TeachingGroup] = {}
        self.research_groups: Dict[str, ResearchGroup] = {}
        self.parent_associations: Dict[str, ParentAssociation] = {}
        self.feedback_items: Dict[str, Feedback] = {}
        self.knowledge_history: Dict[str, List[KnowledgeHistory]] = defaultdict(list)
    
    def register_user(self, username: str, role: UserRole, grade: str = None, 
                     subject: Subject = None) -> User:
        """注册新用户"""
        user_id = str(uuid.uuid4())
        user = User(
            id=user_id,
            username=username,
            role=role,
            grade=grade,
            subject=subject
        )
        self.users[user_id] = user
        return user
    
    def create_knowledge_node(self, title: str, content: str, content_type: ContentType,
                             subject: Subject, difficulty: DifficultyLevel, 
                             prerequisites: List[str], created_by: str,
                             eco_natural: float, eco_humanistic: float, eco_digital: float) -> KnowledgeNode:
        """创建知识节点"""
        # 验证创建者权限
        creator = self.users.get(created_by)
        if not creator or creator.role not in [UserRole.TEACHER, UserRole.RESEARCHER, UserRole.ADMIN]:
            raise PermissionError("只有教师、研究员或管理员可以创建知识节点")
        
        node_id = str(uuid.uuid4())
        now = datetime.now()
        node = KnowledgeNode(
            id=node_id,
            title=title,
            content=content,
            content_type=content_type,
            subject=subject,
            difficulty=difficulty,
            prerequisites=prerequisites,
            eco_aspects={
                EcoType.NATURAL: eco_natural,
                EcoType.HUMANISTIC: eco_humanistic,
                EcoType.DIGITAL: eco_digital
            },
            created_by=created_by,
            created_at=now,
            updated_at=now,
            version=1
        )
        self.knowledge_nodes[node_id] = node
        return node
    
    def create_learning_path(self, name: str, description: str, subject: Subject,
                            target_grade: str, created_by: str,
                            eco_balance: Dict[EcoType, float]) -> LearningPath:
        """创建学习路径"""
        # 验证创建者权限
        creator = self.users.get(created_by)
        if not creator or creator.role not in [UserRole.TEACHER, UserRole.RESEARCHER, UserRole.ADMIN]:
            raise PermissionError("只有教师、研究员或管理员可以创建学习路径")
        
        path_id = str(uuid.uuid4())
        path = LearningPath(
            id=path_id,
            name=name,
            description=description,
            subject=subject,
            target_grade=target_grade,
            nodes=[],
            created_by=created_by,
            eco_balance=eco_balance,
            version=1
        )
        self.learning_paths[path_id] = path
        return path
    
    def create_teaching_group(self, name: str, subject: Subject, grade_level: str, created_by: str) -> TeachingGroup:
        """创建教研组"""
        # 验证创建者权限
        creator = self.users.get(created_by)
        if not creator or creator.role not in [UserRole.TEACHER, UserRole.ADMIN]:
            raise PermissionError("只有教师或管理员可以创建教研组")
        
        group_id = str(uuid.uuid4())
        group = TeachingGroup(
            id=group_id,
            name=name,
            subject=subject,
            grade_level=grade_level,
            members=[created_by],
            created_at=datetime.now()
        )
        self.teaching_groups[group_id] = group
        return group
    
    def create_research_group(self, name: str, focus_areas: List[Subject], created_by: str) -> ResearchGroup:
        """创建科研组"""
        # 验证创建者权限
        creator = self.users.get(created_by)
        if not creator or creator.role not in [UserRole.RESEARCHER, UserRole.ADMIN]:
            raise PermissionError("只有研究员或管理员可以创建科研组")
        
        group_id = str(uuid.uuid4())
        group = ResearchGroup(
            id=group_id,
            name=name,
            focus_areas=focus_areas,
            members=[created_by]
        )
        self.research_groups[group_id] = group
        return group
    
    def create_parent_association(self, school: str, grade: str, created_by: str) -> ParentAssociation:
        """创建家长协会"""
        # 验证创建者权限
        creator = self.users.get(created_by)
        if not creator or creator.role != UserRole.PARENT:
            raise PermissionError("只有家长可以创建家长协会")
        
        association_id = str(uuid.uuid4())
        association = ParentAssociation(
            id=association_id,
            school=school,
            grade=grade,
            members=[created_by]
        )
        self.parent_associations[association_id] = association
        return association
    
    def submit_feedback(self, content: str, created_by: str, target_type: str, 
                       target_id: str, priority: int = 3) -> Feedback:
        """提交反馈"""
        feedback_id = str(uuid.uuid4())
        feedback = Feedback(
            id=feedback_id,
            content=content,
            created_by=created_by,
            created_at=datetime.now(),
            target_type=target_type,
            target_id=target_id,
            priority=priority,
            status="pending"
        )
        self.feedback_items[feedback_id] = feedback
        return feedback
    
    def rate_knowledge_node(self, node_id: str, user_id: str, rating: int) -> bool:
        """对知识节点评分"""
        if rating < 1 or rating > 5:
            raise ValueError("评分必须在1-5之间")
        
        node = self.knowledge_nodes.get(node_id)
        if not node:
            return False
        
        node.ratings[user_id] = rating
        return True
    
    def rate_learning_path(self, path_id: str, user_id: str, rating: int) -> bool:
        """对学习路径评分"""
        if rating < 1 or rating > 5:
            raise ValueError("评分必须在1-5之间")
        
        path = self.learning_paths.get(path_id)
        if not path:
            return False
        
        path.ratings[user_id] = rating
        return True
    
    def update_knowledge_node(self, node_id: str, new_content: str, updated_by: str, 
                             change_description: str = "内容更新") -> bool:
        """更新知识节点内容"""
        node = self.knowledge_nodes.get(node_id)
        if not node:
            return False
        
        # 验证更新者权限
        user = self.users.get(updated_by)
        if not user or user.role not in [UserRole.TEACHER, UserRole.RESEARCHER, UserRole.ADMIN]:
            raise PermissionError("只有教师、研究员或管理员可以更新知识节点")
        
        node.update_content(new_content, updated_by)
        
        # 记录更新历史
        history = KnowledgeHistory(
            node_id=node_id,
            version=node.version,
            content=new_content,
            updated_by=updated_by,
            updated_at=datetime.now(),
            change_description=change_description
        )
        self.knowledge_history[node_id].append(history)
        
        return True
    
    def recommend_content(self, user_id: str, subject: Subject = None, 
                         max_nodes: int = 10) -> List[KnowledgeNode]:
        """基于用户画像和三元生态理念推荐内容"""
        user = self.users.get(user_id)
        if not user:
            return []
        
        # 获取所有相关知识节点
        all_nodes = [node for node in self.knowledge_nodes.values() 
                    if subject is None or node.subject == subject]
        
        # 基于用户生态画像和节点生态评分计算匹配度
        scored_nodes = []
        for node in all_nodes:
            # 计算生态匹配度
            eco_match = 0
            for eco_type in EcoType:
                eco_match += user.eco_profile[eco_type] * node.eco_aspects[eco_type]
            
            # 考虑评分和难度
            rating_weight = node.average_rating() / 5.0
            difficulty_weight = 1.0  # 可以根据用户能力调整
            
            total_score = eco_match * 0.5 + rating_weight * 0.3 + difficulty_weight * 0.2
            scored_nodes.append((node, total_score))
        
        # 按匹配度排序并返回前max_nodes个节点
        scored_nodes.sort(key=lambda x: x[1], reverse=True)
        return [node for node, score in scored_nodes[:max_nodes]]
    
    def generate_eco_report(self, user_id: str) -> Dict:
        """生成用户的三元生态学习报告"""
        user = self.users.get(user_id)
        if not user:
            return {}
        
        # 获取用户访问过的知识节点（在实际系统中需要记录用户行为）
        # 这里简化为所有节点
        accessed_nodes = list(self.knowledge_nodes.values())
        
        # 计算各生态维度的学习情况
        eco_scores = {eco_type: 0 for eco_type in EcoType}
        eco_count = {eco_type: 0 for eco_type in EcoType}
        
        for node in accessed_nodes:
            for eco_type in EcoType:
                if node.eco_aspects[eco_type] > 0.5:  # 只考虑该生态维度显著的知识点
                    eco_scores[eco_type] += node.eco_aspects[eco_type]
                    eco_count[eco_type] += 1
        
        # 计算平均分
        for eco_type in EcoType:
            if eco_count[eco_type] > 0:
                eco_scores[eco_type] /= eco_count[eco_type]
        
        return {
            "user_id": user_id,
            "username": user.username,
            "eco_scores": eco_scores,
            "eco_balance": self.calculate_eco_balance(eco_scores),
            "recommendations": self.generate_eco_recommendations(eco_scores)
        }
    
    def calculate_eco_balance(self, eco_scores: Dict[EcoType, float]) -> str:
        """计算生态平衡状态"""
        total = sum(eco_scores.values())
        if total == 0:
            return "未学习"
        
        natural_ratio = eco_scores[EcoType.NATURAL] / total
        humanistic_ratio = eco_scores[EcoType.HUMANISTIC] / total
        digital_ratio = eco_scores[EcoType.DIGITAL] / total
        
        if abs(natural_ratio - 0.33) < 0.1 and abs(humanistic_ratio - 0.33) < 0.1 and abs(digital_ratio - 0.33) < 0.1:
            return "均衡发展"
        elif natural_ratio > 0.5:
            return "自然生态主导"
        elif humanistic_ratio > 0.5:
            return "人文生态主导"
        elif digital_ratio > 0.5:
            return "数字生态主导"
        else:
            return "偏科发展"
    
    def generate_eco_recommendations(self, eco_scores: Dict[EcoType, float]) -> List[str]:
        """生成生态发展建议"""
        recommendations = []
        min_score_eco = min(eco_scores, key=eco_scores.get)
        
        if eco_scores[min_score_eco] < 0.3:
            if min_score_eco == EcoType.NATURAL:
                recommendations.append("建议增加自然生态相关学习内容，如环境保护、可持续发展等")
            elif min_score_eco == EcoType.HUMANISTIC:
                recommendations.append("建议增加人文生态相关学习内容，如文化传承、社会责任等")
            else:
                recommendations.append("建议增加数字生态相关学习内容，如技术创新、数字化素养等")
        
        # 检查是否均衡发展
        if self.calculate_eco_balance(eco_scores) != "均衡发展":
            recommendations.append("建议关注三元生态的均衡发展，培养全面素养")
        
        return recommendations

# 示例使用
def main():
    # 初始化系统
    system = DynamicTextbookSystem()
    
    # 注册不同角色用户
    teacher1 = system.register_user("张老师", UserRole.TEACHER, subject=Subject.MATH)
    researcher1 = system.register_user("李研究员", UserRole.RESEARCHER, subject=Subject.ECOLOGY)
    student1 = system.register_user("小明", UserRole.STUDENT, grade="七年级")
    parent1 = system.register_user("明父", UserRole.PARENT)
    
    # 设置家长与子女关系
    parent1.children = [student1.id]
    
    # 创建知识节点（由教师创建）
    math_node = system.create_knowledge_node(
        title="勾股定理",
        content="勾股定理是一个基本的几何定理，指直角三角形的两条直角边的平方和等于斜边的平方。",
        content_type=ContentType.TEXT,
        subject=Subject.MATH,
        difficulty=DifficultyLevel.MEDIUM,
        prerequisites=[],
        created_by=teacher1.id,
        eco_natural=0.3,    # 与自然生态关联度
        eco_humanistic=0.7, # 与人文生态关联度（数学文化史）
        eco_digital=0.5     # 与数字生态关联度（计算应用）
    )
    
    # 创建生态教育知识节点（由研究员创建）
    eco_node = system.create_knowledge_node(
        title="可持续发展目标",
        content="可持续发展目标（SDGs）是联合国制定的17个全球发展目标，旨在2030年前解决社会、经济和环境三个维度的发展问题。",
        content_type=ContentType.TEXT,
        subject=Subject.ECOLOGY,
        difficulty=DifficultyLevel.MEDIUM,
        prerequisites=[],
        created_by=researcher1.id,
        eco_natural=0.9,    # 与自然生态关联度高
        eco_humanistic=0.8, # 与人文生态关联度高
        eco_digital=0.4     # 与数字生态关联度中等
    )
    
    # 创建学习路径
    math_path = system.create_learning_path(
        name="初中数学几何入门",
        description="适合初中生的几何学习路径，涵盖基础几何概念和定理",
        subject=Subject.MATH,
        target_grade="七年级",
        created_by=teacher1.id,
        eco_balance={EcoType.NATURAL: 0.3, EcoType.HUMANISTIC: 0.4, EcoType.DIGITAL: 0.3}
    )
    
    # 添加知识节点到学习路径
    math_path.add_node(math_node.id)
    
    # 用户评分
    system.rate_knowledge_node(math_node.id, student1.id, 4)
    system.rate_knowledge_node(eco_node.id, student1.id, 5)
    
    # 家长反馈
    parent_feedback = system.submit_feedback(
        content="勾股定理的示例可以更加生活化，比如如何应用于日常测量",
        created_by=parent1.id,
        target_type="knowledge_node",
        target_id=math_node.id,
        priority=2
    )
    
    # 生成学习推荐
    recommendations = system.recommend_content(student1.id, Subject.MATH)
    print(f"为学生{student1.username}推荐的数学内容:")
    for node in recommendations:
        print(f"- {node.title} (评分: {node.average_rating():.1f})")
    
    # 生成生态报告
    eco_report = system.generate_eco_report(student1.id)
    print(f"\n学生{student1.username}的三元生态学习报告:")
    print(f"自然生态: {eco_report['eco_scores'][EcoType.NATURAL]:.2f}")
    print(f"人文生态: {eco_report['eco_scores'][EcoType.HUMANISTIC]:.2f}")
    print(f"数字生态: {eco_report['eco_scores'][EcoType.DIGITAL]:.2f}")
    print(f"生态平衡: {eco_report['eco_balance']}")
    print("发展建议:")
    for rec in eco_report['recommendations']:
        print(f"- {rec}")

if __name__ == "__main__":
    main()